Skip to content

Add Langfuse observability integration support#187

Open
hijera wants to merge 8 commits intomainfrom
langfuse-updated
Open

Add Langfuse observability integration support#187
hijera wants to merge 8 commits intomainfrom
langfuse-updated

Conversation

@hijera
Copy link
Copy Markdown
Collaborator

@hijera hijera commented Mar 26, 2026

Changes

  • Configuration: Added langfuse flag to AgentConfig for enabling Langfuse tracing

    • Configurable via YAML (langfuse: true/false) or environment variable (SGR__LANGFUSE)
    • Defaults to false
  • Agent Factory: Updated _create_client() to support Langfuse AsyncOpenAI client

    • Uses langfuse.openai.AsyncOpenAI when enabled
    • Falls back gracefully to standard openai.AsyncOpenAI if Langfuse package unavailable
    • Added _patch_langfuse_stream_close() to fix streaming compatibility issues
  • Dependencies: Added langfuse>=4.0.0 to project dependencies

  • Documentation: Added Langfuse configuration guide in English and Russian

    • Explains how to enable/configure Langfuse
    • Documents required environment variables
  • Tests: Added comprehensive test coverage

    • Configuration loading from YAML and environment
    • Langfuse client creation and fallback behavior
    • Integration tests for configuration consistency

Comment on lines +179 to +181
@property
def langfuse_enabled(self) -> bool:
return self.langfuse.enabled
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Выглядит излишним

Comment on lines +84 to +107
if getattr(config, "langfuse_enabled", False):
try:
lf_cfg = config.langfuse
if lf_cfg.public_key or lf_cfg.secret_key or lf_cfg.host:
LangfuseClient = getattr(import_module("langfuse"), "Langfuse")
kwargs = {}
if lf_cfg.public_key:
kwargs["public_key"] = lf_cfg.public_key
if lf_cfg.secret_key:
kwargs["secret_key"] = lf_cfg.secret_key
if lf_cfg.host:
kwargs["host"] = lf_cfg.host
LangfuseClient(**kwargs)
logger.info("Langfuse initialized with explicit credentials from config")
LangfuseAsyncOpenAI = getattr(import_module("langfuse.openai"), "AsyncOpenAI")
cls._patch_langfuse_stream_close()
logger.info("Creating Langfuse AsyncOpenAI client (langfuse_enabled=True)")
return LangfuseAsyncOpenAI(**client_kwargs)
except ImportError:
logger.warning(
"Langfuse is enabled but 'langfuse' package is not available. "
"Falling back to standard AsyncOpenAI client."
)

Copy link
Copy Markdown
Member

@virrius virrius Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Что-то не очень здоровое.

  1. Валидацию можно вынести в модельку
  2. Зачем-то собираются лишние kwargs с лишними if
  3. Если юзер не заимпортил модуль, лучше явно упасть чем неявно фолбекнуться
  4. Какую проблему решает патч stream close?

прогонял на этом тесте, вроде всё работает

    from sgr_agent_core.agent_config import GlobalConfig
    config = GlobalConfig().from_yaml("config.yaml")
    from langfuse import Langfuse
    Langfuse(
        public_key=config.langfuse.public_key,
        secret_key=config.langfuse.secret_key,
        host=config.langfuse.host,
    )
    from langfuse.openai import AsyncOpenAI
    async_client = AsyncOpenAI(
        base_url=config.llm.base_url,
        api_key=config.llm.api_key,
    )
    completion = await async_client.chat.completions.create(
      name="test-chat",
      model="gpt-4o",
      messages=[
          {"role": "system", "content": "Tell me about dirigables"},
          {"role": "user", "content": "Tell me about dirigables"}],
      temperature=0,
      metadata={"someMetadataKey": "someValue"},
      stream=True
    )
    async for chunk in completion:
        print(chunk.choices[0].delta.content, end="")
    print(Langfuse)
    print(completion)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. через kwargs собирается, потому что Langfuse с пустыми параметрами ( когда kwargs будут пустые) инициализируется с env переменными LANGFUSE_SECRET_KEY ,
    LANGFUSE_PUBLIC_KEY ,
    LANGFUSE_BASE_URL .

Copy link
Copy Markdown
Member

@virrius virrius Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. У нас уже есть готовая pydantic моделька, которая в себе это хранит, валидирует и всё такое. Зачем возвращаться обратно к raw словарю?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants